#pragma once

#include "base_type.h"

/****************************************************************************\
 * Image Headers
\****************************************************************************/

#define IMAGE_DOS_SIGNATURE 0x5A4D      // MZ
#define IMAGE_NT_SIGNATURE  0x00004550  // PE00

typedef struct tag_image_dos_header
{
	u2 e_magic;
	u2 e_cblp;
	u2 e_cp;
	u2 e_crlc;
	u2 e_cparhdr;
	u2 e_minalloc;
	u2 e_maxalloc;
	u2 e_ss;
	u2 e_sp;
	u2 e_csum;
	u2 e_ip;
	u2 e_cs;
	u2 e_lfarlc;
	u2 e_ovno;
	u2 e_res[4];
	u2 e_oemid;
	u2 e_oeminfo;
	u2 e_res2[10];
	u4 e_lfanew;
} image_dos_header;

typedef struct tag_image_file_header
{
	u2 Machine;
	u2 NumberOfSections;
	u4 TimeDateStamp;
	u4 PointerToSymbolTable;
	u4 NumberOfSymbols;
	u2 SizeOfOptionalHeader;
	u2 Characteristics;
} image_file_header;

#define IMAGE_FILE_MACHINE_UNKNOWN           0
#define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386.
#define IMAGE_FILE_MACHINE_R3000             0x0162  // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000             0x0166  // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000            0x0168  // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2         0x0169  // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA             0x0184  // Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3               0x01a2  // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP            0x01a3
#define IMAGE_FILE_MACHINE_SH3E              0x01a4  // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4               0x01a6  // SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5               0x01a8  // SH5
#define IMAGE_FILE_MACHINE_ARM               0x01c0  // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB             0x01c2
#define IMAGE_FILE_MACHINE_AM33              0x01d3
#define IMAGE_FILE_MACHINE_POWERPC           0x01F0  // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP         0x01f1
#define IMAGE_FILE_MACHINE_IA64              0x0200  // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16            0x0266  // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64           0x0284  // ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU           0x0366  // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16         0x0466  // MIPS
#define IMAGE_FILE_MACHINE_AXP64             IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE           0x0520  // Infineon
#define IMAGE_FILE_MACHINE_CEF               0x0CEF
#define IMAGE_FILE_MACHINE_EBC               0x0EBC  // EFI Byte Code
#define IMAGE_FILE_MACHINE_AMD64             0x8664  // AMD64 (K8)
#define IMAGE_FILE_MACHINE_M32R              0x9041  // M32R little-endian
#define IMAGE_FILE_MACHINE_CEE               0xC0EE

#define IMAGE_FILE_RELOCS_STRIPPED           0x0001  // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002  // File is executable  (i.e. no unresolved externel references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004  // Line nunbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED       0x0008  // Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM         0x0010  // Agressively trim working set
#define IMAGE_FILE_LARGE_ADDRESS_AWARE       0x0020  // App can handle >2gb addresses
#define IMAGE_FILE_BYTES_REVERSED_LO         0x0080  // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE             0x0100  // 32 bit word machine.
#define IMAGE_FILE_DEBUG_STRIPPED            0x0200  // Debugging info stripped from file in .DBG file
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP   0x0400  // If Image is on removable media, copy and run from the swap file.
#define IMAGE_FILE_NET_RUN_FROM_SWAP         0x0800  // If Image is on Net, copy and run from the swap file.
#define IMAGE_FILE_SYSTEM                    0x1000  // System File.
#define IMAGE_FILE_DLL                       0x2000  // File is a DLL.
#define IMAGE_FILE_UP_SYSTEM_ONLY            0x4000  // File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI         0x8000  // Bytes of machine word are reversed.

typedef struct tag_image_data_directory
{
	u4 VirtualAddress;
	u4 Size;
} image_data_directory;

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16

#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY        4   // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG           6   // Debug Directory
//      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7   // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS             9   // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11   // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT            12   // Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor

typedef struct tag_image_optional_header32
{
	//
	// Standard fields.
	//
	u2 Magic;
	u1 MajorLinkerVersion;
	u1 MinorLinkerVersion;
	u4 SizeOfCode;
	u4 SizeOfInitializedData;
	u4 SizeOfUninitializedData;
	u4 AddressOfEntryPoint;
	u4 BaseOfCode;
	u4 BaseOfData;
	//
	// NT additional fields.
	//
	u4 ImageBase;
	u4 SectionAlignment;
	u4 FileAlignment;
	u2 MajorOperatingSystemVersion;
	u2 MinorOperatingSystemVersion;
	u2 MajorImageVersion;
	u2 MinorImageVersion;
	u2 MajorSubsystemVersion;
	u2 MinorSubsystemVersion;
	u4 Win32VersionValue;
	u4 SizeOfImage;
	u4 SizeOfHeaders;
	u4 CheckSum;
	u2 Subsystem;
	u2 DllCharacteristics;
	u4 SizeOfStackReserve;
	u4 SizeOfStackCommit;
	u4 SizeOfHeapReserve;
	u4 SizeOfHeapCommit;
	u4 LoaderFlags;
	u4 NumberOfRvaAndSizes;
	image_data_directory DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} image_optional_header32;

typedef struct tag_image_optional_header64
{
	//
	// Standard fields.
	//
	u2 Magic;
	u1 MajorLinkerVersion;
	u1 MinorLinkerVersion;
	u4 SizeOfCode;
	u4 SizeOfInitializedData;
	u4 SizeOfUninitializedData;
	u4 AddressOfEntryPoint;
	u4 BaseOfCode;
	//
	// NT additional fields.
	//
	u8 ImageBase;
	u4 SectionAlignment;
	u4 FileAlignment;
	u2 MajorOperatingSystemVersion;
	u2 MinorOperatingSystemVersion;
	u2 MajorImageVersion;
	u2 MinorImageVersion;
	u2 MajorSubsystemVersion;
	u2 MinorSubsystemVersion;
	u4 Win32VersionValue;
	u4 SizeOfImage;
	u4 SizeOfHeaders;
	u4 CheckSum;
	u2 Subsystem;
	u2 DllCharacteristics;
	u8 SizeOfStackReserve;
	u8 SizeOfStackCommit;
	u8 SizeOfHeapReserve;
	u8 SizeOfHeapCommit;
	u4 LoaderFlags;
	u4 NumberOfRvaAndSizes;
	image_data_directory DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} image_optional_header64;

#define IMAGE_NT_OPTIONAL_HDR32_MAGIC      0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC      0x20b

#define IMAGE_SUBSYSTEM_UNKNOWN                  0   // Unknown subsystem.
#define IMAGE_SUBSYSTEM_NATIVE                   1   // Image doesn't require a subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_GUI              2   // Image runs in the Windows GUI subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_CUI              3   // Image runs in the Windows character subsystem.
#define IMAGE_SUBSYSTEM_OS2_CUI                  5   // image runs in the OS/2 character subsystem.
#define IMAGE_SUBSYSTEM_POSIX_CUI                7   // image runs in the Posix character subsystem.
#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS           8   // image is a native Win9x driver.
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI           9   // Image runs in the Windows CE subsystem.
#define IMAGE_SUBSYSTEM_EFI_APPLICATION          10  //
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER  11   //
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER       12  //
#define IMAGE_SUBSYSTEM_EFI_ROM                  13
#define IMAGE_SUBSYSTEM_XBOX                     14
#define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16

#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE          0x0040     // DLL can move.
#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY       0x0080     // Code Integrity Image
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT             0x0100     // Image is NX compatible
#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION          0x0200     // Image understands isolation and doesn't want it
#define IMAGE_DLLCHARACTERISTICS_NO_SEH                0x0400     // Image does not use SEH.  No SE handler may reside in this image
#define IMAGE_DLLCHARACTERISTICS_NO_BIND               0x0800     // Do not bind this image.
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER            0x2000     // Driver uses WDM model
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000

#define IMAGE_SIZEOF_SHORT_NAME 8

typedef struct tag_image_section_header
{
	u1 Name[IMAGE_SIZEOF_SHORT_NAME];
	u4 VirtualSize;
	u4 VirtualAddress;
	u4 SizeOfRawData;
	u4 PointerToRawData;
	u4 PointerToRelocations;
	u4 PointerToLinenumbers;
	u2 NumberOfRelocations;
	u2 NumberOfLinenumbers;
	u4 Characteristics;
} image_section_header;

//      IMAGE_SCN_TYPE_REG                   0x00000000  // Reserved.
//      IMAGE_SCN_TYPE_DSECT                 0x00000001  // Reserved.
//      IMAGE_SCN_TYPE_NOLOAD                0x00000002  // Reserved.
//      IMAGE_SCN_TYPE_GROUP                 0x00000004  // Reserved.
#define IMAGE_SCN_TYPE_NO_PAD                0x00000008  // Reserved.
//      IMAGE_SCN_TYPE_COPY                  0x00000010  // Reserved.

#define IMAGE_SCN_CNT_CODE                   0x00000020  // Section contains code.
#define IMAGE_SCN_CNT_INITIALIZED_DATA       0x00000040  // Section contains initialized data.
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA     0x00000080  // Section contains uninitialized data.

#define IMAGE_SCN_LNK_OTHER                  0x00000100  // Reserved.
#define IMAGE_SCN_LNK_INFO                   0x00000200  // Section contains comments or some other type of information.
//      IMAGE_SCN_TYPE_OVER                  0x00000400  // Reserved.
#define IMAGE_SCN_LNK_REMOVE                 0x00000800  // Section contents will not become part of image.
#define IMAGE_SCN_LNK_COMDAT                 0x00001000  // Section contents comdat.
//                                           0x00002000  // Reserved.
//      IMAGE_SCN_MEM_PROTECTED - Obsolete   0x00004000
#define IMAGE_SCN_NO_DEFER_SPEC_EXC          0x00004000  // Reset speculative exceptions handling bits in the TLB entries for this section.
#define IMAGE_SCN_GPREL                      0x00008000  // Section content can be accessed relative to GP
#define IMAGE_SCN_MEM_FARDATA                0x00008000
//      IMAGE_SCN_MEM_SYSHEAP  - Obsolete    0x00010000
#define IMAGE_SCN_MEM_PURGEABLE              0x00020000
#define IMAGE_SCN_MEM_16BIT                  0x00020000
#define IMAGE_SCN_MEM_LOCKED                 0x00040000
#define IMAGE_SCN_MEM_PRELOAD                0x00080000

#define IMAGE_SCN_ALIGN_1BYTES               0x00100000  //
#define IMAGE_SCN_ALIGN_2BYTES               0x00200000  //
#define IMAGE_SCN_ALIGN_4BYTES               0x00300000  //
#define IMAGE_SCN_ALIGN_8BYTES               0x00400000  //
#define IMAGE_SCN_ALIGN_16BYTES              0x00500000  // Default alignment if no others are specified.
#define IMAGE_SCN_ALIGN_32BYTES              0x00600000  //
#define IMAGE_SCN_ALIGN_64BYTES              0x00700000  //
#define IMAGE_SCN_ALIGN_128BYTES             0x00800000  //
#define IMAGE_SCN_ALIGN_256BYTES             0x00900000  //
#define IMAGE_SCN_ALIGN_512BYTES             0x00A00000  //
#define IMAGE_SCN_ALIGN_1024BYTES            0x00B00000  //
#define IMAGE_SCN_ALIGN_2048BYTES            0x00C00000  //
#define IMAGE_SCN_ALIGN_4096BYTES            0x00D00000  //
#define IMAGE_SCN_ALIGN_8192BYTES            0x00E00000  //
// Unused                                    0x00F00000
#define IMAGE_SCN_ALIGN_MASK                 0x00F00000

#define IMAGE_SCN_LNK_NRELOC_OVFL            0x01000000  // Section contains extended relocations.
#define IMAGE_SCN_MEM_DISCARDABLE            0x02000000  // Section can be discarded.
#define IMAGE_SCN_MEM_NOT_CACHED             0x04000000  // Section is not cachable.
#define IMAGE_SCN_MEM_NOT_PAGED              0x08000000  // Section is not pageable.
#define IMAGE_SCN_MEM_SHARED                 0x10000000  // Section is shareable.
#define IMAGE_SCN_MEM_EXECUTE                0x20000000  // Section is executable.
#define IMAGE_SCN_MEM_READ                   0x40000000  // Section is readable.
#define IMAGE_SCN_MEM_WRITE                  0x80000000  // Section is writeable.

typedef struct tag_image_all_headers32
{
	u4                      Signature;
	image_file_header       FileHeader;
	image_optional_header32 OptionalHeader;
	image_section_header    SectionHeaders[0];
} image_all_headers32;

typedef struct tag_image_all_headers64
{
	u4                      Signature;
	image_file_header       FileHeader;
	image_optional_header64 OptionalHeader;
	image_section_header    SectionHeaders[0];
} image_all_headers64;

/****************************************************************************\
 * Metadata
\****************************************************************************/

typedef struct tag_image_cor20_header
{
	u4                    cb;
	u2                    MajorRuntimeVersion;
	u2                    MinorRuntimeVersion;
	image_data_directory  MetaData;
	u4                    Flags;
	union
	{
		u4                EntryPointToken;
		u4                EntryPointRVA;
	};
	image_data_directory  Resources;
	image_data_directory  StrongNameSignature;
	image_data_directory  CodeManagerTable;  // Depricated, not used 
	image_data_directory  VTableFixups;
	image_data_directory  ExportAddressTableJumps;
	image_data_directory  ManagedNativeHeader;
} image_cor20_header;

#define COMIMAGE_FLAGS_ILONLY            0x00000001
#define COMIMAGE_FLAGS_32BITREQUIRED     0x00000002
#define COMIMAGE_FLAGS_IL_LIBRARY        0x00000004
#define COMIMAGE_FLAGS_STRONGNAMESIGNED  0x00000008
#define COMIMAGE_FLAGS_NATIVE_ENTRYPOINT 0x00000010
#define COMIMAGE_FLAGS_TRACKDEBUGDATA    0x00010000
#define COMIMAGE_FLAGS_ISIBCOPTIMIZED    0x00020000

typedef struct tag_image_cor_vtablefixup
{
	u4 RVA;
	u2 Count;
	u2 Type;
} image_cor_vtablefixup;

#define COR_VTABLE_32BIT                           0x01  // V-table slots are 32-bits in size.   
#define COR_VTABLE_64BIT                           0x02  // V-table slots are 64-bits in size.   
#define COR_VTABLE_FROM_UNMANAGED                  0x04  // If set, transition from unmanaged.
#define COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN 0x08  // NEW
#define COR_VTABLE_CALL_MOST_DERIVED               0x10  // Call most derived method described by

typedef struct tag_metadata_storage_signature
{
	u4   Signature;
	u2   MajorVersion;
	u2   MinorVersion;
	u4   Reserved;
	u4   VersionLength;
	char VersionString[0];
} metadata_storage_signature;

typedef struct tag_metadata_storage_header
{
	u2 Flags;  // Reserved.
	u2 NumberOfStreams;
} metadata_storage_header;

typedef struct tag_metadata_stream_header
{
	u4   Offset;
	u4   Size;
	char Name[0];
} metadata_stream_header;

#define METADATA_MAX_STREAM_NAME_LEN 31

//
// Tabls
//

typedef struct tag_metadata_table_header
{
	u4 Reserved;
	u1 Major;
	u1 Minor;
	u1 Heaps;
	u1 Rid;
	u8 MaskValid;
	u8 MaskSorted;
	u4 TableRows[0];
} metadata_table_header;

typedef enum tag_table_id
{
	TBLID_Module                 ,  // 0x00, 0
	TBLID_TypeRef                ,  // 0x01, 1
	TBLID_TypeDef                ,  // 0x02, 2
	TBLID_FieldPtr               ,  // 0x03, 3
	TBLID_Field                  ,  // 0x04, 4
	TBLID_MethodPtr              ,  // 0x05, 5
	TBLID_Method                 ,  // 0x06, 6
	TBLID_ParamPtr               ,  // 0x07, 7
	TBLID_Param                  ,  // 0x08, 8
	TBLID_InterfaceImpl          ,  // 0x09, 9
	TBLID_MemberRef              ,  // 0x0A, 10
	TBLID_Constant               ,  // 0x0B, 11
	TBLID_CustomAttribute        ,  // 0x0C, 12
	TBLID_FieldMarshal           ,  // 0x0D, 13
	TBLID_DeclSecurity           ,  // 0x0E, 14
	TBLID_ClassLayout            ,  // 0x0F, 15
	TBLID_FieldLayout            ,  // 0x10, 16
	TBLID_StandAloneSig          ,  // 0x11, 17
	TBLID_EventMap               ,  // 0x12, 18
	TBLID_EventPtr               ,  // 0x13, 19
	TBLID_Event                  ,  // 0x14, 20
	TBLID_PropertyMap            ,  // 0x15, 21
	TBLID_PropertyPtr            ,  // 0x16, 22
	TBLID_Property               ,  // 0x17, 23
	TBLID_MethodSemantics        ,  // 0x18, 24
	TBLID_MethodImpl             ,  // 0x19, 25
	TBLID_ModuleRef              ,  // 0x1A, 26
	TBLID_TypeSpec               ,  // 0x1B, 27
	TBLID_ImplMap                ,  // 0x1C, 28
	TBLID_FieldRVA               ,  // 0x1D, 29
	TBLID_ENCLog                 ,  // 0x1E, 30
	TBLID_ENCMap                 ,  // 0x1F, 31
	TBLID_Assembly               ,  // 0x20, 32
	TBLID_AssemblyProcessor      ,  // 0x21, 33
	TBLID_AssemblyOS             ,  // 0x22, 34
	TBLID_AssemblyRef            ,  // 0x23, 35
	TBLID_AssemblyRefProcessor   ,  // 0x24, 36
	TBLID_AssemblyRefOS          ,  // 0x25, 37
	TBLID_File                   ,  // 0x26, 38
	TBLID_ExportedType           ,  // 0x27, 39
	TBLID_ManifestResource       ,  // 0x28, 40
	TBLID_NestedClass            ,  // 0x29, 41
	TBLID_GenericParam           ,  // 0x2A, 42
	TBLID_MethodSpec             ,  // 0x2B, 43
	TBLID_GenericParamConstraint ,  // 0x2C, 44
	NUMBER_OF_METADATA_TABLES    ,  // 0x2D, 45

	TBLID__UNUSED = 0xFFFF
} table_id;

#define NUMBER_OF_METADATA_COLUMNS \
	5 +  /* Module                 */ \
	3 +  /* TypeRef                */ \
	6 +  /* TypeDef                */ \
	1 +  /* FieldPtr               */ \
	3 +  /* Field                  */ \
	1 +  /* MethodPtr              */ \
	6 +  /* Method                 */ \
	1 +  /* ParamPtr               */ \
	3 +  /* Param                  */ \
	2 +  /* InterfaceImpl          */ \
	3 +  /* MemberRef              */ \
	4 +  /* Constant               */ \
	3 +  /* CustomAttribute        */ \
	2 +  /* FieldMarshal           */ \
	3 +  /* DeclSecurity           */ \
	3 +  /* ClassLayout            */ \
	2 +  /* FieldLayout            */ \
	1 +  /* StandAloneSig          */ \
	2 +  /* EventMap               */ \
	1 +  /* EventPtr               */ \
	3 +  /* Event                  */ \
	2 +  /* PropertyMap            */ \
	1 +  /* PropertyPtr            */ \
	3 +  /* Property               */ \
	3 +  /* MethodSemantics        */ \
	3 +  /* MethodImpl             */ \
	1 +  /* ModuleRef              */ \
	1 +  /* TypeSpec               */ \
	4 +  /* ImplMap                */ \
	2 +  /* FieldRVA               */ \
	2 +  /* ENCLog                 */ \
	1 +  /* ENCMap                 */ \
	9 +  /* Assembly               */ \
	1 +  /* AssemblyProcessor      */ \
	3 +  /* AssemblyOS             */ \
	9 +  /* AssemblyRef            */ \
	2 +  /* AssemblyRefProcessor   */ \
	4 +  /* AssemblyRefOS          */ \
	3 +  /* File                   */ \
	5 +  /* ExportedType           */ \
	4 +  /* ManifestResource       */ \
	2 +  /* NestedClass            */ \
	4 +  /* GenericParam           */ \
	2 +  /* MethodSpec             */ \
	2    /* GenericParamConstraint */

typedef enum tag_metadata_column_type_id
{
	// 0-63: RID of each table
	MDCOLT_RID_Module                 = TBLID_Module                 ,  // 0x00, 0
	MDCOLT_RID_TypeRef                = TBLID_TypeRef                ,  // 0x01, 1
	MDCOLT_RID_TypeDef                = TBLID_TypeDef                ,  // 0x02, 2
	MDCOLT_RID_FieldPtr               = TBLID_FieldPtr               ,  // 0x03, 3
	MDCOLT_RID_Field                  = TBLID_Field                  ,  // 0x04, 4
	MDCOLT_RID_MethodPtr              = TBLID_MethodPtr              ,  // 0x05, 5
	MDCOLT_RID_Method                 = TBLID_Method                 ,  // 0x06, 6
	MDCOLT_RID_ParamPtr               = TBLID_ParamPtr               ,  // 0x07, 7
	MDCOLT_RID_Param                  = TBLID_Param                  ,  // 0x08, 8
	MDCOLT_RID_InterfaceImpl          = TBLID_InterfaceImpl          ,  // 0x09, 9
	MDCOLT_RID_MemberRef              = TBLID_MemberRef              ,  // 0x0A, 10
	MDCOLT_RID_Constant               = TBLID_Constant               ,  // 0x0B, 11
	MDCOLT_RID_CustomAttribute        = TBLID_CustomAttribute        ,  // 0x0C, 12
	MDCOLT_RID_FieldMarshal           = TBLID_FieldMarshal           ,  // 0x0D, 13
	MDCOLT_RID_DeclSecurity           = TBLID_DeclSecurity           ,  // 0x0E, 14
	MDCOLT_RID_ClassLayout            = TBLID_ClassLayout            ,  // 0x0F, 15
	MDCOLT_RID_FieldLayout            = TBLID_FieldLayout            ,  // 0x10, 16
	MDCOLT_RID_StandAloneSig          = TBLID_StandAloneSig          ,  // 0x11, 17
	MDCOLT_RID_EventMap               = TBLID_EventMap               ,  // 0x12, 18
	MDCOLT_RID_EventPtr               = TBLID_EventPtr               ,  // 0x13, 19
	MDCOLT_RID_Event                  = TBLID_Event                  ,  // 0x14, 20
	MDCOLT_RID_PropertyMap            = TBLID_PropertyMap            ,  // 0x15, 21
	MDCOLT_RID_PropertyPtr            = TBLID_PropertyPtr            ,  // 0x16, 22
	MDCOLT_RID_Property               = TBLID_Property               ,  // 0x17, 23
	MDCOLT_RID_MethodSemantics        = TBLID_MethodSemantics        ,  // 0x18, 24
	MDCOLT_RID_MethodImpl             = TBLID_MethodImpl             ,  // 0x19, 25
	MDCOLT_RID_ModuleRef              = TBLID_ModuleRef              ,  // 0x1A, 26
	MDCOLT_RID_TypeSpec               = TBLID_TypeSpec               ,  // 0x1B, 27
	MDCOLT_RID_ImplMap                = TBLID_ImplMap                ,  // 0x1C, 28
	MDCOLT_RID_FieldRVA               = TBLID_FieldRVA               ,  // 0x1D, 29
	MDCOLT_RID_ENCLog                 = TBLID_ENCLog                 ,  // 0x1E, 30
	MDCOLT_RID_ENCMap                 = TBLID_ENCMap                 ,  // 0x1F, 31
	MDCOLT_RID_Assembly               = TBLID_Assembly               ,  // 0x20, 32
	MDCOLT_RID_AssemblyProcessor      = TBLID_AssemblyProcessor      ,  // 0x21, 33
	MDCOLT_RID_AssemblyOS             = TBLID_AssemblyOS             ,  // 0x22, 34
	MDCOLT_RID_AssemblyRef            = TBLID_AssemblyRef            ,  // 0x23, 35
	MDCOLT_RID_AssemblyRefProcessor   = TBLID_AssemblyRefProcessor   ,  // 0x24, 36
	MDCOLT_RID_AssemblyRefOS          = TBLID_AssemblyRefOS          ,  // 0x25, 37
	MDCOLT_RID_File                   = TBLID_File                   ,  // 0x26, 38
	MDCOLT_RID_ExportedType           = TBLID_ExportedType           ,  // 0x27, 39
	MDCOLT_RID_ManifestResource       = TBLID_ManifestResource       ,  // 0x28, 40
	MDCOLT_RID_NestedClass            = TBLID_NestedClass            ,  // 0x29, 41
	MDCOLT_RID_GenericParam           = TBLID_GenericParam           ,  // 0x2A, 42
	MDCOLT_RID_MethodSpec             = TBLID_MethodSpec             ,  // 0x2B, 43
	MDCOLT_RID_GenericParamConstraint = TBLID_GenericParamConstraint ,  // 0x2C, 44

	// 64-95: Coded Token
	MDCOLT_CT_TypeDefOrRef            = 64,
	MDCOLT_CT_HasConstant             = 65,
	MDCOLT_CT_HasCustomAttribute      = 66,
	MDCOLT_CT_HasFieldMarshal         = 67,
	MDCOLT_CT_HasDeclSecurity         = 68,
	MDCOLT_CT_MemberRefParent         = 69,
	MDCOLT_CT_HasSemantics            = 70,
	MDCOLT_CT_MethodDefOrRef          = 71,
	MDCOLT_CT_MemberForwarded         = 72,
	MDCOLT_CT_Implementation          = 73,
	MDCOLT_CT_CustomAttributeType     = 74,
	MDCOLT_CT_ResolutionScope         = 75,
	MDCOLT_CT_TypeOrMethodDef         = 76,

	MDCOLT_I2                         = 96,
	MDCOLT_U2                         = 97,
	MDCOLT_I4                         = 98,
	MDCOLT_U4                         = 99,
	MDCOLT_U1                         = 100,
	MDCOLT_S_STRINGS                  = 101,
	MDCOLT_S_GUID                     = 102,
	MDCOLT_S_BLOB                     = 103,

	MDCOLT_RID__MIN   = MDCOLT_RID_Module,
	MDCOLT_RID__MAX   = MDCOLT_RID_GenericParamConstraint,
	MDCOLT_RID__COUNT = MDCOLT_RID__MAX - MDCOLT_RID__MIN + 1,

	MDCOLT_CT__MIN    = MDCOLT_CT_TypeDefOrRef,
	MDCOLT_CT__MAX    = MDCOLT_CT_TypeOrMethodDef,
	MDCOLT_CT__COUNT  = MDCOLT_CT__MAX - MDCOLT_CT__MIN + 1,

	MDCOLT_S__MIN     = MDCOLT_S_STRINGS,
	MDCOLT_S__MAX     = MDCOLT_S_BLOB,
	MDCOLT_S__COUNT   = MDCOLT_S__MAX - MDCOLT_S__MIN + 1,
} metadata_column_type_id;

typedef enum tag_metadata_column_type_ex_id
{
	MDCOLTEX__NONE,
	MDCOLTEX_RVA,

	MDCOLTEX_TypeFlags,              // cor_type_flags
	MDCOLTEX_FieldFlags,             // cor_field_flags
	MDCOLTEX_MethodImplFlags,        // cor_method_impl_flags
	MDCOLTEX_MethodFlags,            // cor_method_flags
	MDCOLTEX_ParamFlags,             // cor_param_flags
	MDCOLTEX_EventFlags,             // cor_event_flags
	MDCOLTEX_PropertyFlags,          // cor_property_flags
	MDCOLTEX_MethodSemanticsFlags,   // cor_method_semantics_flags
	MDCOLTEX_PInvokeMapFlags,        // cor_pinvoke_map_flags
	MDCOLTEX_AssemblyFlags,          // cor_assembly_flags
	MDCOLTEX_FileFlags,              // cor_file_flags
	MDCOLTEX_ManifestResourceFlags,  // cor_manifest_resource_flags
	MDCOLTEX_GenericParamFlags,      // cor_generic_param_flags
	MDCOLTEX_HashAlg,                // cor_hash_alg_id
	MDCOLTEX_SecurityAction,         // cor_security_action
	MDCOLTEX_ElementType,            // cor_element_type
} metadata_column_type_ex_id;

typedef struct tag_mdt_col_def
{
	str_wc                     name;
	metadata_column_type_id    type;
	metadata_column_type_ex_id ex_type;
	u1                         offset;
	u1                         size;
} mdt_col_def;

typedef struct tag_mdt_tbl_def
{
	str_wc           name;
	u2               cols;  // First column definitions in the mdt_col_def array.
	u1               record_size;
	u4               record_num;
	struct
	{
		u1           col_num :  6;
		u1           is_valid:  1;
		u1           is_sorted: 1;
	};
	u1               rid_size;
	byte            *p_data;
} mdt_tbl_def;

typedef struct tag_coded_token_def
{
	str_wc name;
	u1     tag_size;
	u1     tag_mask;
	u1     tbl_num;
	u1     col_size;
	u2     record_limit;
	u2     tables;  // First referenced table id in the array.
} coded_token_def;

typedef struct tag_coded_token_ref_tbl_def
{
	u2       num_in_token;
	table_id table_id;  // 0xFFFF means not used.
} coded_token_ref_tbl_def;

#define NUMBER_OF_CODED_TOKEN_REF_TBL \
	3  +  /* TypeDefOrRef        */  \
	3  +  /* HasConstant         */  \
	22 +  /* HasCustomAttribute  */  \
	2  +  /* HasFieldMarshal     */  \
	3  +  /* HasDeclSecurity     */  \
	5  +  /* MemberRefParent     */  \
	2  +  /* HasSemantics        */  \
	2  +  /* MethodDefOrRef      */  \
	2  +  /* MemberForwarded     */  \
	3  +  /* Implementation      */  \
	5  +  /* CustomAttributeType */  \
	4  +  /* ResolutionScope     */  \
	2	  /* TypeOrMethodDef     */

//
// Metadata table column flags
//

// TypeDef.Flags, ExportedType.Flags
typedef enum tag_cor_type_flags
{
    // Use this mask to retrieve the type visibility information.
    tdVisibilityMask        =   0x00000007,
    tdNotPublic             =   0x00000000,     // Class is not public scope.
    tdPublic                =   0x00000001,     // Class is public scope.
    tdNestedPublic          =   0x00000002,     // Class is nested with public visibility.
    tdNestedPrivate         =   0x00000003,     // Class is nested with private visibility.
    tdNestedFamily          =   0x00000004,     // Class is nested with family visibility.
    tdNestedAssembly        =   0x00000005,     // Class is nested with assembly visibility.
    tdNestedFamANDAssem     =   0x00000006,     // Class is nested with family and assembly visibility.
    tdNestedFamORAssem      =   0x00000007,     // Class is nested with family or assembly visibility.

    // Use this mask to retrieve class layout information
    tdLayoutMask            =   0x00000018,
    tdAutoLayout            =   0x00000000,     // Class fields are auto-laid out
    tdSequentialLayout      =   0x00000008,     // Class fields are laid out sequentially
    tdExplicitLayout        =   0x00000010,     // Layout is supplied explicitly
    // end layout mask

    // Use this mask to retrieve class semantics information.
    tdClassSemanticsMask    =   0x00000020,
    tdClass                 =   0x00000000,     // Type is a class.
    tdInterface             =   0x00000020,     // Type is an interface.
    // end semantics mask

    // Special semantics in addition to class semantics.
    tdAbstract              =   0x00000080,     // Class is abstract
    tdSealed                =   0x00000100,     // Class is concrete and may not be extended
    tdSpecialName           =   0x00000400,     // Class name is special.  Name describes how.

    // Implementation attributes.
    tdImport                =   0x00001000,     // Class / interface is imported
    tdSerializable          =   0x00002000,     // The class is Serializable.

    // Use tdStringFormatMask to retrieve string information for native interop
    tdStringFormatMask      =   0x00030000,
    tdAnsiClass             =   0x00000000,     // LPTSTR is interpreted as ANSI in this class
    tdUnicodeClass          =   0x00010000,     // LPTSTR is interpreted as UNICODE
    tdAutoClass             =   0x00020000,     // LPTSTR is interpreted automatically
    tdCustomFormatClass     =   0x00030000,     // A non-standard encoding specified by CustomFormatMask
    tdCustomFormatMask      =   0x00C00000,     // Use this mask to retrieve non-standard encoding information for native interop. The meaning of the values of these 2 bits is unspecified.

    // end string format mask

    tdBeforeFieldInit       =   0x00100000,     // Initialize the class any time before first static field access.
    tdForwarder             =   0x00200000,     // This ExportedType is a type forwarder.

    // Flags reserved for runtime use.
    tdReservedMask          =   0x00040800,
    tdRTSpecialName         =   0x00000800,     // Runtime should check name encoding.
    tdHasSecurity           =   0x00040000,     // Class has security associate with it.
} cor_type_flags;

// Field.Flags
typedef enum tag_cor_field_flags
{
    // member access mask - Use this mask to retrieve accessibility information.
    fdFieldAccessMask           =   0x0007,
    fdPrivateScope              =   0x0000,     // Member not referenceable.
    fdPrivate                   =   0x0001,     // Accessible only by the parent type.
    fdFamANDAssem               =   0x0002,     // Accessible by sub-types only in this Assembly.
    fdAssembly                  =   0x0003,     // Accessibly by anyone in the Assembly.
    fdFamily                    =   0x0004,     // Accessible only by type and sub-types.
    fdFamORAssem                =   0x0005,     // Accessibly by sub-types anywhere, plus anyone in assembly.
    fdPublic                    =   0x0006,     // Accessibly by anyone who has visibility to this scope.
    // end member access mask

    // field contract attributes.
    fdStatic                    =   0x0010,     // Defined on type, else per instance.
    fdInitOnly                  =   0x0020,     // Field may only be initialized, not written to after init.
    fdLiteral                   =   0x0040,     // Value is compile time constant.
    fdNotSerialized             =   0x0080,     // Field does not have to be serialized when type is remoted.

    fdSpecialName               =   0x0200,     // field is special.  Name describes how.

    // interop attributes
    fdPinvokeImpl               =   0x2000,     // Implementation is forwarded through pinvoke.

    // Reserved flags for runtime use only.
    fdReservedMask              =   0x9500,
    fdRTSpecialName             =   0x0400,     // Runtime(metadata internal APIs) should check name encoding.
    fdHasFieldMarshal           =   0x1000,     // Field has marshalling information.
    fdHasDefault                =   0x8000,     // Field has default.
    fdHasFieldRVA               =   0x0100,     // Field has RVA.
} cor_field_flags;

// Method.ImplFlags
typedef enum tag_cor_method_impl_flags
{
    // code impl mask
    miCodeTypeMask      =   0x0003,   // Flags about code type.
    miIL                =   0x0000,   // Method impl is IL.
    miNative            =   0x0001,   // Method impl is native.
    miOPTIL             =   0x0002,   // Method impl is OPTIL
    miRuntime           =   0x0003,   // Method impl is provided by the runtime.
    // end code impl mask

    // managed mask
    miManagedMask       =   0x0004,   // Flags specifying whether the code is managed or unmanaged.
    miUnmanaged         =   0x0004,   // Method impl is unmanaged, otherwise managed.
    miManaged           =   0x0000,   // Method impl is managed.
    // end managed mask

    // implementation info and interop
    miForwardRef        =   0x0010,   // Indicates method is defined; used primarily in merge scenarios.
    miPreserveSig       =   0x0080,   // Indicates method sig is not to be mangled to do HRESULT conversion.

    miInternalCall      =   0x1000,   // Reserved for internal use.

    miSynchronized      =   0x0020,   // Method is single threaded through the body.
    miNoInlining        =   0x0008,   // Method may not be inlined.
    miNoOptimization    =   0x0040,   // Method may not be optimized.
    miMaxMethodImplVal  =   0xffff,   // Range check value
} cor_method_impl_flags;

// Method.Flags
typedef enum tag_cor_method_flags
{
    // member access mask - Use this mask to retrieve accessibility information.
    mdMemberAccessMask          =   0x0007,
    mdPrivateScope              =   0x0000,     // Member not referenceable.
    mdPrivate                   =   0x0001,     // Accessible only by the parent type.
    mdFamANDAssem               =   0x0002,     // Accessible by sub-types only in this Assembly.
    mdAssem                     =   0x0003,     // Accessibly by anyone in the Assembly.
    mdFamily                    =   0x0004,     // Accessible only by type and sub-types.
    mdFamORAssem                =   0x0005,     // Accessibly by sub-types anywhere, plus anyone in assembly.
    mdPublic                    =   0x0006,     // Accessibly by anyone who has visibility to this scope.
    // end member access mask

    // method contract attributes.
    mdStatic                    =   0x0010,     // Defined on type, else per instance.
    mdFinal                     =   0x0020,     // Method may not be overridden.
    mdVirtual                   =   0x0040,     // Method virtual.
    mdHideBySig                 =   0x0080,     // Method hides by name+sig, else just by name.

    // vtable layout mask - Use this mask to retrieve vtable attributes.
    mdVtableLayoutMask          =   0x0100,
    mdReuseSlot                 =   0x0000,     // The default.
    mdNewSlot                   =   0x0100,     // Method always gets a new slot in the vtable.
    // end vtable layout mask

    // method implementation attributes.
    mdCheckAccessOnOverride     =   0x0200,     // Overridability is the same as the visibility.
    mdAbstract                  =   0x0400,     // Method does not provide an implementation.
    mdSpecialName               =   0x0800,     // Method is special.  Name describes how.

    // interop attributes
    mdPinvokeImpl               =   0x2000,     // Implementation is forwarded through pinvoke.
    mdUnmanagedExport           =   0x0008,     // Managed method exported via thunk to unmanaged code.

    // Reserved flags for runtime use only.
    mdReservedMask              =   0xd000,
    mdRTSpecialName             =   0x1000,     // Runtime should check name encoding.
    mdHasSecurity               =   0x4000,     // Method has security associate with it.
    mdRequireSecObject          =   0x8000,     // Method calls another method containing security code.
} cor_method_flags;

// Param.Flags
typedef enum tag_cor_param_flags
{
    pdIn                        =   0x0001,     // Param is [In]
    pdOut                       =   0x0002,     // Param is [out]
    pdOptional                  =   0x0010,     // Param is optional

    // Reserved flags for Runtime use only.
    pdReservedMask              =   0xf000,
    pdHasDefault                =   0x1000,     // Param has default value.
    pdHasFieldMarshal           =   0x2000,     // Param has FieldMarshal.

    pdUnused                    =   0xcfe0,
} cor_param_flags;

// Event.Flags
typedef enum tag_cor_event_flags
{
    evSpecialName           =   0x0200,     // event is special.  Name describes how.

    // Reserved flags for Runtime use only.
    evReservedMask          =   0x0400,
    evRTSpecialName         =   0x0400,     // Runtime(metadata internal APIs) should check name encoding.
} cor_event_flags;

// Property.Flags
typedef enum tag_cor_property_flags
{
    prSpecialName           =   0x0200,     // property is special.  Name describes how.

    // Reserved flags for Runtime use only.
    prReservedMask          =   0xf400,
    prRTSpecialName         =   0x0400,     // Runtime(metadata internal APIs) should check name encoding.
    prHasDefault            =   0x1000,     // Property has default

    prUnused                =   0xe9ff,
} cor_property_flags;

// MethodSemantics.Semantic
typedef enum tag_cor_method_semantics_flags
{
    msSetter    =   0x0001,     // Setter for property
    msGetter    =   0x0002,     // Getter for property
    msOther     =   0x0004,     // other method for property or event
    msAddOn     =   0x0008,     // AddOn method for event
    msRemoveOn  =   0x0010,     // RemoveOn method for event
    msFire      =   0x0020,     // Fire method for event
} cor_method_semantics_flags;

// ImplMap.MappingFlags
typedef enum  tag_cor_pinvoke_map_flags
{
    pmNoMangle          = 0x0001,   // Pinvoke is to use the member name as specified.

    // Use this mask to retrieve the CharSet information.
    pmCharSetMask       = 0x0006,
    pmCharSetNotSpec    = 0x0000,
    pmCharSetAnsi       = 0x0002,
    pmCharSetUnicode    = 0x0004,
    pmCharSetAuto       = 0x0006,


    pmBestFitUseAssem   = 0x0000,
    pmBestFitEnabled    = 0x0010,
    pmBestFitDisabled   = 0x0020,
    pmBestFitMask       = 0x0030,

    pmThrowOnUnmappableCharUseAssem   = 0x0000,
    pmThrowOnUnmappableCharEnabled    = 0x1000,
    pmThrowOnUnmappableCharDisabled   = 0x2000,
    pmThrowOnUnmappableCharMask       = 0x3000,

    pmSupportsLastError = 0x0040,   // Information about target function. Not relevant for fields.

    // None of the calling convention flags is relevant for fields.
    pmCallConvMask      = 0x0700,
    pmCallConvWinapi    = 0x0100,   // Pinvoke will use native callconv appropriate to target windows platform.
    pmCallConvCdecl     = 0x0200,
    pmCallConvStdcall   = 0x0300,
    pmCallConvThiscall  = 0x0400,   // In M9, pinvoke will raise exception.
    pmCallConvFastcall  = 0x0500,

    pmMaxValue          = 0xFFFF,
} cor_pinvoke_map_flags;

// DeclSecurity.Action
// System.Security.Permissions.SecurityAction
typedef enum tag_cor_security_action
{
	saRequest                 = 0x0001,
	saDemand                  = 0x0002,
	saAssert                  = 0x0003,
	saDeny                    = 0x0004,
	saPermitOnly              = 0x0005,
	saLinkDemand              = 0x0006,
	saInheritanceDemand       = 0x0007,
	saRequestMinimum          = 0x0008,
	saRequestOptional         = 0x0009,
	saRequestRefuse           = 0x000A,
	saPreJitGrant             = 0x000B,
	saPreJitDeny              = 0x000C,
	saNonCasDemand            = 0x000D,
	saNonCasLinkDemand        = 0x000E,
	saNonCasInheritanceDemand = 0x000F,
} cor_security_action;

// Assembly.Flags, AssemblyRef.Flags
typedef enum tag_cor_assembly_flags
{
    afPublicKey             =   0x0001,     // The assembly ref holds the full (unhashed) public key.
    
    afPA_None               =   0x0000,     // Processor Architecture unspecified
    afPA_MSIL               =   0x0010,     // Processor Architecture: neutral (PE32)
    afPA_x86                =   0x0020,     // Processor Architecture: x86 (PE32)
    afPA_IA64               =   0x0030,     // Processor Architecture: Itanium (PE32+)
    afPA_AMD64              =   0x0040,     // Processor Architecture: AMD X64 (PE32+)
    afPA_NoPlatform         =   0x0070,      // applies to any platform but cannot run on any (e.g. reference assembly), should not have "specified" set
    afPA_Specified          =   0x0080,     // Propagate PA flags to AssemblyRef record
    afPA_Mask               =   0x0070,     // Bits describing the processor architecture
    afPA_FullMask           =   0x00F0,     // Bits describing the PA incl. Specified
    afPA_Shift              =   0x0004,     // NOT A FLAG, shift count in PA flags <--> index conversion

    afEnableJITcompileTracking  =   0x8000, // From "DebuggableAttribute".
    afDisableJITcompileOptimizer=   0x4000, // From "DebuggableAttribute".

    afRetargetable          =   0x0100,     // The assembly can be retargeted (at runtime) to an
                                            //  assembly from a different publisher.
} cor_assembly_flags;

// File.Flags
typedef enum tag_cor_file_flags
{
    ffContainsMetaData      =   0x0000,     // This is not a resource file
    ffContainsNoMetaData    =   0x0001,     // This is a resource file or other non-metadata-containing file
} cor_file_flags;

// ManifestResource.Flags
typedef enum tag_cor_manifest_resource_flags
{
    mrVisibilityMask        =   0x0007,
    mrPublic                =   0x0001,     // The Resource is exported from the Assembly.
    mrPrivate               =   0x0002,     // The Resource is private to the Assembly.
} cor_manifest_resource_flags;

// GenericParam.Flags
typedef enum tag_cor_generic_param_flags
{
    // Variance of type parameters, only applicable to generic parameters 
    // for generic interfaces and delegates
    gpVarianceMask          =   0x0003,
    gpNonVariant            =   0x0000, 
    gpCovariant             =   0x0001,
    gpContravariant         =   0x0002,

    // Special constraints, applicable to any type parameters
    gpSpecialConstraintMask =  0x001C,
    gpNoSpecialConstraint   =   0x0000,      
    gpReferenceTypeConstraint = 0x0004,      // type argument must be a reference type
    gpNotNullableValueTypeConstraint   =   0x0008,      // type argument must be a value type but not Nullable
    gpDefaultConstructorConstraint = 0x0010, // type argument must have a public default constructor
} cor_generic_param_flags;

// Constant.Type
typedef enum tag_cor_element_type
{
	ELEMENT_TYPE_END            = 0x00,
	ELEMENT_TYPE_VOID           = 0x01,
	ELEMENT_TYPE_BOOLEAN        = 0x02,
	ELEMENT_TYPE_CHAR           = 0x03,
	ELEMENT_TYPE_I1             = 0x04,
	ELEMENT_TYPE_U1             = 0x05,
	ELEMENT_TYPE_I2             = 0x06,
	ELEMENT_TYPE_U2             = 0x07,
	ELEMENT_TYPE_I4             = 0x08,
	ELEMENT_TYPE_U4             = 0x09,
	ELEMENT_TYPE_I8             = 0x0a,
	ELEMENT_TYPE_U8             = 0x0b,
	ELEMENT_TYPE_R4             = 0x0c,
	ELEMENT_TYPE_R8             = 0x0d,
	ELEMENT_TYPE_STRING         = 0x0e,

	// every type above PTR will be simple type
	ELEMENT_TYPE_PTR            = 0x0f,     // PTR <type>
	ELEMENT_TYPE_BYREF          = 0x10,     // BYREF <type>

	// Please use ELEMENT_TYPE_VALUETYPE. ELEMENT_TYPE_VALUECLASS is deprecated.
	ELEMENT_TYPE_VALUETYPE      = 0x11,     // VALUETYPE <class Token>
	ELEMENT_TYPE_CLASS          = 0x12,     // CLASS <class Token>
	ELEMENT_TYPE_VAR            = 0x13,     // a class type variable VAR <number>
	ELEMENT_TYPE_ARRAY          = 0x14,     // MDARRAY <type> <rank> <bcount> <bound1> ... <lbcount> <lb1> ...
	ELEMENT_TYPE_GENERICINST    = 0x15,     // GENERICINST <generic type> <argCnt> <arg1> ... <argn>
	ELEMENT_TYPE_TYPEDBYREF     = 0x16,     // TYPEDREF  (it takes no args) a typed referece to some other type

	ELEMENT_TYPE_I              = 0x18,     // native integer size
	ELEMENT_TYPE_U              = 0x19,     // native unsigned integer size
	ELEMENT_TYPE_FNPTR          = 0x1b,     // FNPTR <complete sig for the function including calling convention>
	ELEMENT_TYPE_OBJECT         = 0x1c,     // Shortcut for System.Object
	ELEMENT_TYPE_SZARRAY        = 0x1d,     // Shortcut for single dimension zero lower bound array
	                                        // SZARRAY <type>
	ELEMENT_TYPE_MVAR           = 0x1e,     // a method type variable MVAR <number>

	// This is only for binding
	ELEMENT_TYPE_CMOD_REQD      = 0x1f,     // required C modifier : E_T_CMOD_REQD <mdTypeRef/mdTypeDef>
	ELEMENT_TYPE_CMOD_OPT       = 0x20,     // optional C modifier : E_T_CMOD_OPT <mdTypeRef/mdTypeDef>

	// This is for signatures generated internally (which will not be persisted in any way).
	ELEMENT_TYPE_INTERNAL       = 0x21,     // INTERNAL <typehandle>

	// Note that this is the max of base type excluding modifiers
	ELEMENT_TYPE_MAX            = 0x22,     // first invalid element type


	ELEMENT_TYPE_MODIFIER       = 0x40,
	ELEMENT_TYPE_SENTINEL       = 0x01 | ELEMENT_TYPE_MODIFIER, // sentinel for varargs
	ELEMENT_TYPE_PINNED         = 0x05 | ELEMENT_TYPE_MODIFIER,
	ELEMENT_TYPE_R4_HFA         = 0x06 | ELEMENT_TYPE_MODIFIER, // used only internally for R4 HFA types
	ELEMENT_TYPE_R8_HFA         = 0x07 | ELEMENT_TYPE_MODIFIER, // used only internally for R8 HFA types
} cor_element_type;

// Assembly.HashAlgId
typedef enum tag_cor_hash_alg_id
{
	haNone = 0x00000000,
	haMD5  = 0x00008003,
	haSha1 = 0x00008004,
} cor_hash_alg_id;

//
// Metadata Root
//

typedef struct tag_metadata_content
{
	image_cor20_header            *p_cli_hdr;
	metadata_storage_signature    *p_st_sig;
	metadata_storage_header       *p_st_hdr;
	metadata_stream_header        *p_stream_hdr;
	metadata_table_header         *p_table_hdr;
	byte                          *p_table_data;

	size_t   table_offset;
	size_t   table_length;
	size_t strings_offset;
	size_t strings_length;
	size_t      us_offset;
	size_t      us_length;
	size_t    guid_offset;
	size_t    guid_length;
	size_t    blob_offset;
	size_t    blob_length;

	mdt_tbl_def             tbl_defs[NUMBER_OF_METADATA_TABLES];
	mdt_col_def             col_defs[NUMBER_OF_METADATA_COLUMNS];
	coded_token_def         coded_tokens[MDCOLT_CT__COUNT];
	coded_token_ref_tbl_def coded_token_ref_tbls[NUMBER_OF_CODED_TOKEN_REF_TBL];
	u1 stream_type_size[MDCOLT_S__COUNT];
} metadata_content;

//
// Metadata Token
//

typedef enum tag_mdt_token_type
{
	MDT_Module                 = TBLID_Module                 << 24,  // 0x00000000
	MDT_TypeRef                = TBLID_TypeRef                << 24,  // 0x01000000
	MDT_TypeDef                = TBLID_TypeDef                << 24,  // 0x02000000
	MDT_Field                  = TBLID_Field                  << 24,  // 0x04000000
	MDT_Method                 = TBLID_Method                 << 24,  // 0x06000000
	MDT_Param                  = TBLID_Param                  << 24,  // 0x08000000
	MDT_InterfaceImpl          = TBLID_InterfaceImpl          << 24,  // 0x09000000
	MDT_MemberRef              = TBLID_MemberRef              << 24,  // 0x0A000000
	MDT_CustomAttribute        = TBLID_CustomAttribute        << 24,  // 0x0C000000
	MDT_DeclSecurity           = TBLID_DeclSecurity           << 24,  // 0x0E000000
	MDT_StandAloneSig          = TBLID_StandAloneSig          << 24,  // 0x11000000
	MDT_Event                  = TBLID_Event                  << 24,  // 0x14000000
	MDT_Property               = TBLID_Property               << 24,  // 0x17000000
	MDT_ModuleRef              = TBLID_ModuleRef              << 24,  // 0x1A000000
	MDT_TypeSpec               = TBLID_TypeSpec               << 24,  // 0x1B000000
	MDT_Assembly               = TBLID_Assembly               << 24,  // 0x20000000
	MDT_AssemblyRef            = TBLID_AssemblyRef            << 24,  // 0x23000000
	MDT_File                   = TBLID_File                   << 24,  // 0x26000000
	MDT_ExportedType           = TBLID_ExportedType           << 24,  // 0x27000000
	MDT_ManifestResource       = TBLID_ManifestResource       << 24,  // 0x28000000
	MDT_GenericParam           = TBLID_GenericParam           << 24,  // 0x2A000000
	MDT_MethodSpec             = TBLID_MethodSpec             << 24,  // 0x2B000000
	MDT_GenericParamConstraint = TBLID_GenericParamConstraint << 24,  // 0x2C000000
	MDT_String                 = 0x70000000,
	MDT__MASK                  = 0xFF000000
} mdt_token_type;

//
// IL methods
//

typedef enum tag_cor_il_method_flags
{
	CorILMethod_InitLocals      = 0x0010,           // call default constructor on all local vars
	CorILMethod_MoreSects       = 0x0008,           // there is another attribute after this one

	CorILMethod_CompressedIL    = 0x0040,           // Not used.  

	// Indicates the format for the COR_ILMETHOD header
	CorILMethod_FormatShift     = 3,
	CorILMethod_FormatMask      = ((1 << CorILMethod_FormatShift) - 1),
	CorILMethod_TinyFormat      = 0x0002,         // use this code if the code size is even
	CorILMethod_SmallFormat     = 0x0000,
	CorILMethod_FatFormat       = 0x0003,
	CorILMethod_TinyFormat1     = 0x0006,         // use this code if the code size is odd
} cor_il_method_flags;

typedef union IMAGE_COR_ILMETHOD_TINY
{
	u1           Flags_CodeSize;
	struct
	{
		unsigned Flags   : 2;
		unsigned CodeSize: 6;
	};
} IMAGE_COR_ILMETHOD_TINY;

typedef struct IMAGE_COR_ILMETHOD_FAT
{
	union
	{
		u4           Flags_Size_MaxStack;
		struct
		{
			unsigned Flags    : 12;     // Flags see code:CorILMethodFlags
			unsigned Size     :  4;     // size in DWords of this structure (currently 3)
			unsigned MaxStack : 16;     // maximum number of items (I4, I, I8, obj ...), on the operand stack
		};
	};
	u4               CodeSize;           // size of the code
	u4               LocalVarSigTok;     // token that indicates the signature of the local vars (0 means none)
} IMAGE_COR_ILMETHOD_FAT;

typedef union IMAGE_COR_ILMETHOD
{
	u1                            Flags;
	IMAGE_COR_ILMETHOD_TINY       Tiny;
	IMAGE_COR_ILMETHOD_FAT        Fat;
} IMAGE_COR_ILMETHOD;

#define COR_ILMETHOD_IS_FAT(/*IMAGE_COR_ILMETHOD*/ h) \
	(((h)->Flags & CorILMethod_FormatMask) == CorILMethod_FatFormat)

#define COR_ILMETHOD_HAS_MORE_SECT(/*IMAGE_COR_ILMETHOD*/ h) \
	((((h)->Flags & CorILMethod_FormatMask) == CorILMethod_FatFormat) \
	&& ((h)->Flags & CorILMethod_MoreSects))

typedef enum CorILMethodSect                             // codes that identify attributes
{
	CorILMethod_Sect_Reserved    = 0,
	CorILMethod_Sect_EHTable     = 1,
	CorILMethod_Sect_OptILTable  = 2,

	CorILMethod_Sect_KindMask    = 0x3F,        // The mask for decoding the type code
	CorILMethod_Sect_FatFormat   = 0x40,        // fat format
	CorILMethod_Sect_MoreSects   = 0x80,        // there is another attribute after this one
} CorILMethodSect;

typedef struct IMAGE_COR_ILMETHOD_SECT_SMALL
{
	u1 Kind;
	u1 DataSize;
} IMAGE_COR_ILMETHOD_SECT_SMALL;

typedef struct IMAGE_COR_ILMETHOD_SECT_FAT
{
	unsigned Kind : 8;
	unsigned DataSize : 24;
} IMAGE_COR_ILMETHOD_SECT_FAT;

typedef enum CorExceptionFlag                       // defintitions for the Flags field below (for both big and small)
{
	COR_ILEXCEPTION_CLAUSE_NONE,                    // This is a typed handler
	COR_ILEXCEPTION_CLAUSE_OFFSETLEN = 0x0000,      // Deprecated
	COR_ILEXCEPTION_CLAUSE_DEPRECATED = 0x0000,     // Deprecated
	COR_ILEXCEPTION_CLAUSE_FILTER  = 0x0001,        // If this bit is on, then this EH entry is for a filter
	COR_ILEXCEPTION_CLAUSE_FINALLY = 0x0002,        // This clause is a finally clause
	COR_ILEXCEPTION_CLAUSE_FAULT = 0x0004,          // Fault clause (finally that is called on exception only)
	COR_ILEXCEPTION_CLAUSE_DUPLICATED = 0x0008,     // duplicated clase..  this clause was duplicated down to a funclet which was pulled out of line
} CorExceptionFlag;

typedef struct IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL
{
	unsigned     Flags:16;
	unsigned     TryOffset:16;
	unsigned     TryLength:8;      // relative to start of try block
	unsigned     HandlerOffset:16;
	unsigned     HandlerLength:8;  // relative to start of handler
	union
	{
		u4      ClassToken;    // Flags=NONE
		u4      FilterOffset;  // Flags=FILTER
	};
} IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL;

typedef struct IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT
{
	u4     Flags;
	u4     TryOffset;
	u4     TryLength;      // relative to start of try block
	u4     HandlerOffset;
	u4     HandlerLength;  // relative to start of handler
	union
	{
		u4 ClassToken;     // use for type-based exception handlers
		u4 FilterOffset;   // use for filter-based exception handlers (COR_ILEXCEPTION_FILTER is set)
	};
} IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT;

typedef struct IMAGE_COR_ILMETHOD_SECT_EH_SMALL
{
	IMAGE_COR_ILMETHOD_SECT_SMALL SectSmall;
	u2 Padding;
	IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL Clauses[1];   // actually variable size
} IMAGE_COR_ILMETHOD_SECT_EH_SMALL;

typedef struct IMAGE_COR_ILMETHOD_SECT_EH_FAT
{
	IMAGE_COR_ILMETHOD_SECT_FAT   SectFat;
	IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT Clauses[1];     // actually variable size
} IMAGE_COR_ILMETHOD_SECT_EH_FAT;

typedef union IMAGE_COR_ILMETHOD_SECT_EH
{
	IMAGE_COR_ILMETHOD_SECT_EH_SMALL Small;
	IMAGE_COR_ILMETHOD_SECT_EH_FAT Fat;
} IMAGE_COR_ILMETHOD_SECT_EH;

typedef struct tag_il_method
{
	IMAGE_COR_ILMETHOD *p_hdr;
	byte *p_body;
	union
	{
		byte *p_sect;
		IMAGE_COR_ILMETHOD_SECT_EH *p_sect_eh;
	};
} il_method;

/****************************************************************************\
 * PE File
\****************************************************************************/

typedef struct tag_pe_file
{
	size_t                   length;

	union
	{
		byte                *p_base;
		image_dos_header    *p_dos_header;
	};
	union
	{
		image_all_headers32 *p_headers32;
		image_all_headers64 *p_headers64;
	};

	u4                      *p_signature;
	image_file_header       *p_file_hdr;
	image_data_directory    *p_data_dir;
	image_section_header    *p_sect_hdr;

	metadata_content         metadata;
} pe_file;

/****************************************************************************\
 * Functions - PE File
\****************************************************************************/

#define IS_64BIT_PE(p_pe) \
	((p_pe)->p_headers64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)

/*
 * Set content of a PE file.
 *
 * Parameters:
 *   p_pe    - Pointer to the pe_file structure need to set content.
 *   content - Bytes contents of the PE file.
 *   len     - Length (in bytes) of the PE file.
 *
 * Returns: TRUE for success, FALSE for error.
 */
BOOL set_pe_file_content(pe_file *p_pe, byte *content, size_t len);

/*
 * Check whether a PE file is valid and print error as needed.
 *
 * Parameters:
 *   p_pe    - Pointer to the pe_file structure need to check.
 *
 * Returns: TRUE for success, FALSE for error.
 */
BOOL check_pe_headers(pe_file *p_pe);

/****************************************************************************\
 * Functions - Metadata
\****************************************************************************/

#define CONTAINS_METADATA(p_pe) \
	((p_pe)->p_data_dir[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress > 0)

BOOL set_metadata(pe_file *p_pe);
BOOL check_metadata(pe_file *p_pe);
metadata_stream_header *next_stream_header(metadata_stream_header *p);

str_wc get_metadata_table_name(u2 tid);

/*
 * Get row data pointer to a specified table
 *
 * Parameters:
 *   p_pe - Pointer to the pe_file structure.
 *   tid  - Id of the table to get row data.
 *   rid  - 1-based row id.
 *
 * Returns: Pointer to the row data.
 */
byte *get_metadata_table_row_data(pe_file *p_pe, table_id tid, size_t rid);
#define METADATA_TOKEN_TID(token) ((token) >> 24)
#define METADATA_TOKEN_RID(token) ((token) & 0x00FFFFFF);
#define METADATA_TOKEN_STR_LEN 100
BOOL format_metadata_token(pe_file *p_pe, u4 token, str_w str_buf, size_t str_len);
void format_metadata_token_direct(u4 token, str_w str_buf, size_t str_len);

/****************************************************************************\
 * Functions - IL
\****************************************************************************/

BOOL get_il_method(pe_file *p_pe, size_t rid_method, il_method *p_il);
byte *next_il_method_sect(pe_file *p_pe, byte *sect);

/****************************************************************************\
 * Functions - Utilities
\****************************************************************************/

/*
 * Get information of an RVA.
 *
 * Parameters:
 *   p_pe          - Pointer to the pe_file structure.
 *   rva           - The RVA value.
 *   pp_sec        - (Out) Pointer to the section pointer, where the RVA live in.
 *   p_sec_offset  - (Out) Pointer to the offset that related to the section start.
 *   p_file_offset - (Out) Pointer to the offset that related to the file start.
 *
 * Returns: TRUE for success, FALSE for error.
 *
 * Remarks: If the section of the RVA was not found, pointee of pp_sec,
 *          p_sec_offset, and p_file_offset would be set to 0.
 */
void get_rva_info(pe_file *p_pe, u4 rva,
	image_section_header **pp_sec, size_t *p_sec_offset, size_t *p_file_offset);

void get_offset_info(pe_file *p_pe, u4 offset,
	image_section_header **pp_sec, size_t *p_sec_offset, size_t *p_rva);

size_t rva_to_offset(pe_file *p_pe, u4 rva);

#define RVA_STR_LEN 50

size_t format_rva_str(pe_file *p_pe, u4 rva, str_w str_buf, size_t buf_size);

#define DATA_DIRECTORY_STR_LEN 100

size_t format_data_dir(pe_file *p_pe, image_data_directory *ddir,
	str_w str_buf, size_t buf_size);

byte *round_to(byte *pointer, size_t alignment);
